package blockchain

import (
	"context"
	"crypto/ecdsa"
	"encoding/hex"
	"fmt"
	"private-domain-overseas-service/pkg/xerr"

	"private-domain-overseas-service/app/business/api/internal/repository/blockchain"
	"private-domain-overseas-service/app/business/api/internal/svc"
	"private-domain-overseas-service/app/business/api/internal/types"
	mycommon "private-domain-overseas-service/pkg/common"
	"private-domain-overseas-service/tools/ent"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/logx"
)

type BlockchainCreateWalletLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// 创建区块链钱包
func NewBlockchainCreateWalletLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BlockchainCreateWalletLogic {
	return &BlockchainCreateWalletLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

// generateWallet 生成以太坊钱包
func (l *BlockchainCreateWalletLogic) generateWallet() (*ecdsa.PrivateKey, common.Address, error) {
	// 生成私钥
	privateKey, err := crypto.GenerateKey()
	if err != nil {
		return nil, common.Address{}, errors.Wrap(err, "生成私钥失败")
	}

	// 从私钥获取公钥
	publicKey := privateKey.Public()
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		return nil, common.Address{}, errors.Wrap(err, "获取公钥失败")
	}

	// 从公钥获取地址
	address := crypto.PubkeyToAddress(*publicKeyECDSA)

	return privateKey, address, nil
}

func (l *BlockchainCreateWalletLogic) BlockchainCreateWallet() (resp *types.BlockchainCreateWalletResponse, err error) {
	userID := mycommon.JwtAuthUserId(l.ctx)
	blockchainWalletDao := blockchain.NewBlockchainWalletDao(l.ctx, l.svcCtx)

	// 生成新钱包
	privateKey, address, err := l.generateWallet()
	if err != nil {
		return nil, xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, fmt.Sprintf("生成第三方钱包失败:%v", err.Error()))
	}
	privateKeyHex := hex.EncodeToString(crypto.FromECDSA(privateKey))

	// 使用事务创建钱包
	err = mycommon.WithTx(l.ctx, l.svcCtx.Orm, func(tx *ent.Tx) error {
		createBlockchainWallet := &ent.HzBlockchainWallet{
			UserID:           userID,
			WalletAddress:    address.Hex(),
			WalletPrivateKey: privateKeyHex,
			WalletStatus:     1,
		}
		_, err = blockchainWalletDao.CreateBlockchainWallet(tx, createBlockchainWallet)
		return err
	})
	if err != nil {
		return nil, xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, fmt.Sprintf("写入数据库钱包失败:%v", err.Error()))
	}

	return &types.BlockchainCreateWalletResponse{
		Address:    address.Hex(),
		PrivateKey: privateKeyHex,
	}, nil
}
